<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Controller;

use App\Common\RedisKey;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Hyperf\Utils\ApplicationContext;
use Psr\Container\ContainerInterface;

abstract class AbstractController
{
    /**
     * @Inject
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @Inject
     * @var RequestInterface
     */
    protected $request;

    /**
     * @Inject
     * @var ResponseInterface
     */
    protected $response;

    public function __construct() {
        $this->check();
    }

    /**
     * 签名验证
     */
    public function check() {
        return;
        $params = $this->request->all();
        zlog('request_params:请求参数', $params);
        //获取访问的文件路径 http://192.168.31.163:9501/home/index/index?age=1&name=jiang  => /home/index/index
        $action = $this->request->getRequestUri();
        if(! isset($params['sign']) || empty($params['sign'])) {
            abort(999, '缺少必要参数sign');
        }
        $sign = $params['sign'];

        if(!isset($params['timestamp']) || empty($params['timestamp'])) {
            abort(999, '缺少必要参数timestamp');
        }
        $appEnv = env('APP_ENV');
        //开发环境不验证签名过期时间
        /*if ($appEnv != 'dev') {
             if($params['timestamp'] < (time() - 120)) {//TimeStamp为当前时间加30秒，30秒后过期
                 abort(0, 'App项目签名过期');
             }
        }*/
        $expectSign = $this->getSign($params);
        var_dump($expectSign);
        if($expectSign != $sign) {
            zlog('签名错误-sing-error', $expectSign);
            abort(999, 'App项目签名错误');
        }
    }


    /**
     * 获取签名
     * @param $params
     */
    private function getSign($params) {
        $row = [
            'appkey'       => 'user',
            'security_key' => 'ee11cbb19052e40b07aac0ca060c23ee',
            'status'       => 1,
        ];
        if($row['status'] <> 1){
            abort(999, 'App项目已经关闭');
        }
        $sign = $this->encrypt($params, $row['security_key']);
        return $sign;
    }


    /**
     * 生成签名
     * @param array $params
     * @param string $s_key
     * 规则:
     * 1.对除签名外的所有请求参数按key做的升序排列,value无需编码。
     * 例如：有c=3,b=2,a=1 三个参，另加上时间戳后， 按key升序排序后为：a=1，b=2，c=3，timestamp=12345678。
     * 2 把参数名和参数值连接成字符串，得到拼装字符：a1b2c3timestamp12345678
     * 3 用服务端发放的SecurityKey(安全码)连接到接拼装字符串头部和尾部，然后进行32位MD5加密，最后将到得MD5加密摘要转化成大写。
     * 示例：假设SecurityKey=test，md5(testa1b2c3timestamp12345678test)，生成的字符串即为Sign(签名)
     */
    private function encrypt(array $params, string $s_key) {
        unset($params['sign']);
        ksort($params);
        $encrypt_str = '';
        foreach($params as $key => $value){
            $encrypt_str .= $key.$value;
        }
        $encrypt_str = $s_key.$encrypt_str.$s_key;
        //echo $encrypt_str;
        return md5($encrypt_str);
    }


    /**
     * 请求成功
     * @param array  $data
     * @param string $message
     * @return array
     */
    public function success($data = [], $msg = 'success') {
        $code = $this->response->getStatusCode();
        $result = [
            'code' => $code,
            'msg'  => $msg,
            //'data' => $data ? $data : new \stdClass(),
            'data' => is_array($data) && empty($data) ? (object)$data : $data,
        ];
        return $result;
    }

    /**
     * 请求失败
     * @param string $msg
     * @return array
     */
    public function error($msg = 'Request format error!')
    {
        $code = $this->response->getStatusCode();
        $result = [
            'code' => $code,
            'msg' => $msg,
            'data' => new \ArrayObject()
        ];
        return $result;
    }

    /**
     * 检查用户token
     */
    public function checkUserToken() {
        $appEnv = env('APP_ENV');
        if (in_array($appEnv, ['local', 'test', 'prod'])) {
            $container = ApplicationContext::getContainer();
            $this->request = $container->get(RequestInterface::class);
            $userToken = $this->request->input('user_token');
            if (empty($userToken)) abort(999, 'user_token 不能为空');

            $redis = $container->get(\Hyperf\Redis\Redis::class);
            //$redis = make(Redis::class);
            $key = RedisKey::getUserToken($userToken);
            $userInfo = $redis->hGetAll($key);
            if(! $userInfo) abort(1061);
            if($userInfo['status'] != 1) abort(1060);
            return $userInfo['user_id'];
        }
    }

}
